package github.saw96x.provider.Impl;

import github.saw96x.common.enums.RpcErrorMessageEnum;
import github.saw96x.common.exception.RpcException;
import github.saw96x.common.extension.ExtensionLoader;
import github.saw96x.config.RpcServiceConfig;
import github.saw96x.provider.ServiceProvider;
import github.saw96x.registry.ServiceRegistry;
import github.saw96x.remoting.transport.netty.server.NettyRpcServer;
import lombok.extern.slf4j.Slf4j;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Saw96x
 * @date 2022/3/18 8:34
 */
@Slf4j
public class ZkServiceProviderImpl implements ServiceProvider {

  /**
   * key: rpc service name(interface name + version + group)
   * value: service object
   */
  private final Map<String, Object> serviceMap;
  private final Set<String> registeredService;
  private final ServiceRegistry serviceRegistry;

  public ZkServiceProviderImpl() {
    serviceMap = new ConcurrentHashMap<>();
    registeredService = ConcurrentHashMap.newKeySet();
    serviceRegistry = ExtensionLoader.getExtensionLoader(ServiceRegistry.class).getExtension("zk");
  }

  @Override
  public void addService(RpcServiceConfig rpcServiceConfig) {
    String rpcServiceName = rpcServiceConfig.getRpcServiceName();
    if (registeredService.contains(rpcServiceName)) {
      return;
    }
    registeredService.add(rpcServiceName);
    serviceMap.put(rpcServiceName, rpcServiceConfig.getService());
    log.info("Add service: {} and interfaces:{}", rpcServiceName, rpcServiceConfig.getService().getClass().getInterfaces());
  }

  @Override
  public Object getService(String rpcServiceName) {
    Object service = serviceMap.get(rpcServiceName);
    if (null == service) {
      throw new RpcException(RpcErrorMessageEnum.SERVICE_CAN_NOT_BE_FOUND);
    }
    return service;
  }

  @Override
  public void publishService(RpcServiceConfig rpcServiceConfig) {
    try {
      String host = InetAddress.getLocalHost().getHostAddress();
      this.addService(rpcServiceConfig);
      serviceRegistry.registerService(rpcServiceConfig.getRpcServiceName(), new InetSocketAddress(host, NettyRpcServer.PORT));
    } catch (UnknownHostException e) {
      log.error("occur exception when getHostAddress", e);
    }
  }

}
